﻿using FileSC.Win.api;
using System;
using System.Diagnostics;
using System.Windows.Forms;

namespace FileSC.Win.hooks
{
    /// <summary>
    /// 全局鼠标钩子
    /// </summary>
    /// <remarks>
    /// 使用须知： 需及时进行释放Hook钩子，原则上执行操作后应立即进行释放操作，已最大程度防止卡顿。
    /// </remarks>
    public class MouseHook
    {
        private int hHook = 0;
        private const int WM_MOUSEMOVE = 0x200;
        private const int WM_LBUTTONDOWN = 0x201;
        private const int WM_RBUTTONDOWN = 0x204;
        private const int WM_MBUTTONDOWN = 0x207;
        private const int WM_LBUTTONUP = 0x202;
        private const int WM_RBUTTONUP = 0x205;
        private const int WM_MBUTTONUP = 0x208;
        private const int WM_LBUTTONDBLCLK = 0x203;
        private const int WM_RBUTTONDBLCLK = 0x206;
        private const int WM_MBUTTONDBLCLK = 0x209;

        public const int WH_MOUSE_LL = 14;
        internal Win32Api.HookProc hProc;
        internal bool hooked {get;set;}
        public MouseHook()
        {
            hProc = new Win32Api.HookProc(MouseHookProc);
            GC.KeepAlive(hProc);
        }
        ~MouseHook()
        {
            if (hHook != 0)
            {
                UnHook();
            }

            GC.SuppressFinalize(hProc);
            hProc = null;
        }
        public int SetHook()
        {
            if (!hooked)
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                hHook = Win32Api.SetWindowsHookEx(WH_MOUSE_LL, hProc, Win32Api.GetModuleHandle(curModule.ModuleName), 0);
                hooked = true;
                return hHook;
            }

            return 0;
        }
        public void UnHook()
        {
            hooked = false;
            Win32Api.UnhookWindowsHookEx(hHook);
        }
        private int MouseHookProc(int nCode, int wParam, IntPtr lParam)
        {
            try
            {
                if (hooked) 
                if (wParam == WM_LBUTTONUP || wParam == WM_RBUTTONUP || wParam == WM_MBUTTONUP)
                {
                    MouseUpEvent?.Invoke(this, null);
                }

                return hooked ? Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam) : 0;
            }
            catch (Exception)
            {
                return 0;
            }
        }
        public delegate void MouseUpHandler(object sender, MouseEventArgs e);
        public event MouseUpHandler MouseUpEvent;
    }
}
